package com.ms.p2p.service.impl;

import com.ms.common.exception.NoticeException;
import com.ms.common.utils.MsDateUtils;
import com.ms.p2p.bean.PageBean;
import com.ms.p2p.bean.Stay;
import com.ms.p2p.dao.LoanDao;
import com.ms.p2p.dao.LoanImgDao;
import com.ms.p2p.dao.MemberDao;
import com.ms.p2p.dao.RedPacketDao;
import com.ms.p2p.entity.loan.*;
import com.ms.p2p.entity.member.Member;
import com.ms.p2p.entity.system.AdminUser;
import com.ms.p2p.enums.AccountFLow;
import com.ms.p2p.enums.AccountType;
import com.ms.p2p.enums.LoanRepayStyle;
import com.ms.p2p.enums.LoanStatus;
import com.ms.p2p.provider.LoanDueInProvider;
import com.ms.p2p.provider.LoanStayProvider;
import com.ms.p2p.provider.LoanTenderRecordProvider;
import com.ms.p2p.provider.MemberAccountProvider;
import com.ms.p2p.utils.AverageCapitalPlusInterestUtils;
import com.ms.p2p.utils.LoanStayInfo;
import com.ms.p2p.utils.impl.LoanDueInInfo;
import com.ms.p2p.utils.impl.StayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;

@Service
@Transactional(readOnly = true)
public class LoanServiceImpl {

    @Autowired
    private LoanTenderRecordServiceImpl loanTenderRecordService;
    @Autowired
    private LoanDueInServiceImpl loanDueInService;
    @Autowired
    private MemberAccountServiceImpl memberAccountService;
    @Autowired
    private LoanDao borrowDao;

    @Autowired
    private MemberDao memberDao;

    @Autowired
    private LoanImgDao borrowImgDao;

    @Autowired
    private MemberServiceImpl memberService;
    @Autowired
    private LoanStayServiceImpl loanStayService;


    @Autowired
    private LoanDueInInfo loanDueInInfo;
    @Autowired
    private LoanStayInfo loanStayInfo;

    @Autowired
    private RedPacketServiceImpl redPacketService;
    @Autowired
    private SettingServiceImpl settingService;


    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void successLoan(Loan borrow, List<LoanTenderRecord> borrowTenderList,String ip) {

        // 扣除投标的冻结的投标的金额
        for (LoanTenderRecord loanTender : borrowTenderList) {
            memberAccountService.OperAccount(ip,loanTender.getSuccess_money(),loanTender.getUser_id(), "标的<a href='/bid/detail/" + borrow.getId() + "'>【" + borrow.getName() + "】</a>复审通过，支出投标金额￥" + loanTender.getSuccess_money() + "。", AccountType.invest.getValue(), AccountFLow.FLOW_OUT.getValue());
            memberAccountService.OperAccount(ip,loanTender.getBack_payment(),loanTender.getUser_id(),"标的<a href='/bid/detail/" + borrow.getId() + "'>【" + borrow.getName() + "】</a>复审通过，增加待收￥" + loanTender.getBack_payment() + "。",AccountType.add_col.getValue(),AccountFLow.FLOW_COL.getValue());
        }
        memberAccountService.OperAccount(ip,borrow.getAccount(), borrow.getUser_id(),"标的<a   target='_blank'href='/bid/detail/" + borrow.getId() + "'>【" + borrow.getName() + "】</a>满标复审通过，获得借款￥" + borrow.getAccount(),AccountType.borrow_success.getValue(),AccountFLow.FLOW_IN.getValue());
    }

    /***
     * 发放奖励
     **/
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void awardForTender(Loan loan, List<LoanTenderRecord> tenderList,String ip) {
        for (LoanTenderRecord borrowTender : tenderList) {
            BigDecimal rate = borrowTender.getSuccess_money().divide(loan.getAccount(), 10, 4);
            BigDecimal account = loan.getAccount().multiply(loan.getRadio_account().divide(BigDecimal.valueOf(100L).setScale(10, 4)))
                    .setScale(2, 4).multiply(rate).setScale(2, 4);
            // 判断是否有奖励
            if (account.compareTo(new BigDecimal(0)) != 0) {
                memberAccountService.OperAccount(ip,account,loan.getUser_id(), "标的<a target='_blank' href='/bid/detail/" + loan.getId() + "'>【" + loan.getName() + "】</a>满标复审通过,支付￥" + account + "。",AccountType.award_lower.getValue(),AccountFLow.FLOW_OUT.getValue());
                memberAccountService.OperAccount(ip,account,borrowTender.getUser_id(),"标的<a  target='_blank' href='/bid/detail/" + loan.getId() + "'>【" + loan.getName() + "】</a>投标奖励￥" + account + "。",AccountType.award_add.getValue(),AccountFLow.FLOW_IN.getValue());
                borrowTender.setAward(account);
                loanTenderRecordService.update(borrowTender);
            }

//            Double award_ratio = Double.valueOf(settingService.findByCode("award_ratio").getText());
//
//            Integer recommend_id = memberService.findById(borrowTender.getUser_id()).getRecommend_id();
//            if(award_ratio>0) {
//                if (recommend_id != null) {
//
////				邀请奖励规则
////				邀请好友注册并参与投资，即可获得邀请奖励。好友投资，您可获得该笔投资年化投资额2%的邀请奖励，好友越多，获得的奖励也越多。
////				天标年化投资额=投资金额*投资期限/365
////				月标年化投资额=投资金额*投资期限/12
//
//                    BigDecimal money = BigDecimal.ZERO;
//                    if (loan.getIs_day() == 0) {
//                        money = borrowTender.getSuccess_money().multiply(new BigDecimal(loan.getTime_limit())).divide(new BigDecimal(12), 5, RoundingMode.HALF_UP).multiply(new BigDecimal(award_ratio)).divide(new BigDecimal(100));
//                    } else {
//                        money = borrowTender.getSuccess_money().multiply(new BigDecimal(loan.getTime_limit())).divide(new BigDecimal(365), 5, RoundingMode.HALF_UP).multiply(new BigDecimal(award_ratio)).divide(new BigDecimal(100));
//                        ;
//                    }
//                    memberAccountService.OperAccount(ip, money, recommend_id, "邀请者投资奖励", "inviter_award", "in");
//                    memberDao.awardforInviter(money,borrowTender.getUser_id());
//                }
//            }
        }


    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int overBorrow(Loan borrow) {
        return borrowDao.over(borrow.getAmount_invested(), MsDateUtils.getTime(), borrow.getId());

    }

    /**
     * 投标核心方法
     **/
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int tender(BigDecimal successAmount, Integer id) {
        return borrowDao.tender(successAmount, MsDateUtils.getTime(), id);
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int insert(Loan map) {
        return borrowDao.insert(map);

    }
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public List<Map<String, Object>> findPager(String borrowId, String userName, Integer userId, Integer borrowType,
                                               Integer borrowStatus, Integer timeLimitBegin, Integer timeLimitEnd,
                                               Integer aprBegin, Integer aprEnd, Integer lowestAccountBegin,
                                               Integer lowestAccountEnd, Integer borrowStyle, String begin_time,
                                               String end_time, PageBean borrowPage) {

        return borrowDao.findPager(borrowId, userName, userId, borrowType, borrowStatus, timeLimitBegin,
                timeLimitEnd, aprBegin, aprEnd, lowestAccountBegin, lowestAccountEnd, borrowStyle, begin_time,
                end_time, borrowPage.getBegin(), borrowPage.getPageSize());
    }
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public Integer findCount(String borrowId, String userName, Integer userId, Integer borrowType,
                             Integer borrowStatus, Integer timeLimitBegin, Integer timeLimitEnd,
                             Integer aprBegin, Integer aprEnd, Integer lowestAccountBegin,
                             Integer lowestAccountEnd, Integer borrowStyle, String begin_time,
                             String end_time) {
        return borrowDao.findCount(borrowId, userName, userId, borrowType, borrowStatus,
                timeLimitBegin, timeLimitEnd, aprBegin, aprEnd, lowestAccountBegin,
                lowestAccountEnd, borrowStyle, begin_time, end_time);
    }


    /**
     * 根据ID查询borrow信息
     *
     * @param id
     * @return
     */
    public Loan findById(String id) {
        return borrowDao.get(id);
    }

    /**
     * 修改标的信息
     *
     * @param map
     * @return
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int update(Loan map) {
        return borrowDao.update(map);
    }

    /**
     * 修改标的信息
     *
     * @param map
     * @return
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int updateOptimistic(Loan map) {
        return borrowDao.updateOptimistic(map);
    }

    /**
     * 插入图片
     *
     * @param map
     * @return
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int insertImg(LoanImg map) {
        return borrowImgDao.insert(map);

    }

    /**
     * 查询某个标的所有图片
     *
     * @return
     */
    public List<LoanImg> findImgByBorrowId(Integer borrow_id) {
        return borrowImgDao.getByBorrowId(borrow_id);

    }

    /**
     * 删除某个标下的所有图片
     *
     * @return
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public int delImgByBorrowId(Integer borrow_id) {
        return borrowImgDao.delByBorrowId(borrow_id);

    }




    /**
     * 撤销招标，解冻投资人的投资金额
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void calculateFailBid(String ip, Loan borrow) {
        List<LoanTenderRecord> borrowTenderList = loanTenderRecordService
                .getTenderLog(borrow.getId());
        for (LoanTenderRecord borrowTender : borrowTenderList) {

            memberAccountService.OperAccount(ip,borrowTender.getSuccess_money(),
                    borrowTender.getUser_id(),"流标<a  target='_blank' href='/bid/detail/" + borrow.getId() + "'>【"
                            + borrow.getName() + "】</a>" + "得到,￥"
                            + borrowTender.getSuccess_money() + "。",AccountType.invest_false.getValue(),AccountFLow.FLOW_THAW.getValue());
            loanTenderRecordService.update(borrowTender);
        }

    }

    /**
     * 累计交易额
     */
    public Map<String, Object> totalMoney() {
        return borrowDao.totalMoney();

    }
    /**
     * 累计交易额
     */

    public Integer count(String userId,String status) {
        return borrowDao.count(userId,status);

    }


    /**
     * 生成待还表记录
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void addStay(Loan loan,String ip) {

        int time_limit = loan.getTime_limit();// 借款期限
        if(loan.getPay_style().equals("0")){
            LoanStay repayment = loanStayInfo.lumpSumDebt(loan,ip);
            loanStayService.insert(repayment);
        }else{
            for (int i = 0; i < time_limit; i++) {
                LoanStay repayment = null;
                if (loan.getPay_style().equals("1")) {
                    repayment = loanStayInfo.equalPrincipalAndInterest(loan, i,ip);
                } else if (loan.getPay_style().equals("3")) {
                    repayment = loanStayInfo.FirstCouponLaterEdition(loan, i,ip);
                } else if (
                        loan.getPay_style().equals(LoanRepayStyle.STYLE_4.getValue().toString())
                        || loan.getPay_style().equals(LoanRepayStyle.STYLE_5.getValue().toString())
                        || loan.getPay_style().equals(LoanRepayStyle.STYLE_6.getValue().toString())) {
                    //等本等息（不提前还款）
                    String stayTime = MsDateUtils.getMonthTime(i+1);
                    //等本等息（提前还款一个月）
                    if(loan.getPay_style().equals(LoanRepayStyle.STYLE_4.getValue().toString())){
//                        if(i==0){
//                            stayTime = MsDateUtils.getDayTimeRepay(0);
//                        }else{
                            stayTime = MsDateUtils.getMonthTime(i);
                      //  }
                    }
                    //等本等息（提前还款两个月）
                    else if(loan.getPay_style().equals(LoanRepayStyle.STYLE_6.getValue().toString())){
                        if(i==0 || i==1){
                            stayTime = MsDateUtils.getDayTimeRepay(0);
                        }else{
                            stayTime = MsDateUtils.getMonthTime(i-1);
                        }
                    }
                    repayment = loanStayInfo.equalInstallmentPayment(loan, i, stayTime,ip);
                }
                loanStayService.insert(repayment);
            }
        }

        Stay stay  = StayUtil.getMoney(loan,0);
        stay.setOrder(1);
        borrowDao.updateStay(stay,loan.getId());
    }

    /**
     * 生成待收表记录
     *
     * @param loan
     * @return
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void addDueRecord(Loan loan,String ip) {
        // 查出投标记录
        List<LoanTenderRecord> borrowTenderList = loanTenderRecordService.getTenderLog(loan.getId());
        int time_limit = loan.getTime_limit();// 借款期限
        if (!loan.getPay_style().equals("0")) {
            for (int i = 0; i < time_limit; i++) {
                for (LoanTenderRecord borrowTender : borrowTenderList) {
                    LoanDueIn borrowDueIn = null;
                    //等额本息
                    if (loan.getPay_style().equals(LoanRepayStyle.STYLE_1.getValue().toString())) {
                        borrowDueIn = loanDueInInfo.equalPrincipalAndInterest(loan, borrowTender, i,ip);
                    }
                    //按月付息到期还本
                    else if (loan.getPay_style().equals(LoanRepayStyle.STYLE_3.getValue().toString())) {
                        borrowDueIn = loanDueInInfo.FirstCouponLaterEdition(loan, borrowTender, i,ip);
                    }
                    //等本等息
                    else if (loan.getPay_style().equals(LoanRepayStyle.STYLE_4.getValue().toString())
                            || loan.getPay_style().equals(LoanRepayStyle.STYLE_5.getValue().toString())
                            || loan.getPay_style().equals(LoanRepayStyle.STYLE_6.getValue().toString())) {
                        //等本等息（不提前还款）
                        String dueinTime = MsDateUtils.getMonthTime(i+1);
                        //等本等息（提前还款一个月）
                        if(loan.getPay_style().equals(LoanRepayStyle.STYLE_4.getValue().toString())){
//                            if(i==0){
//                                dueinTime = MsDateUtils.getDayTimeRepay(0);
//                            }else{
                            dueinTime = MsDateUtils.getMonthTime(i);
                            // }
                        }

                        else if(loan.getPay_style().equals(LoanRepayStyle.STYLE_6.getValue().toString())){
                            if(i==0 || i==1){
                                dueinTime = MsDateUtils.getDayTimeRepay(0);
                            }else{
                                dueinTime = MsDateUtils.getMonthTime(i-1);
                            }
                        }
                        borrowDueIn = loanDueInInfo.equalInstallmentPayment(loan, borrowTender, i, dueinTime,ip);
                    }
                    loanDueInService.insert(borrowDueIn);
                }
            }
        } else {
            for (LoanTenderRecord borrowTender : borrowTenderList) {
                LoanDueIn borrowDueIn = loanDueInInfo.lumpSumDebt(loan, borrowTender,ip);
                loanDueInService.insert(borrowDueIn);
            }
        }

    }

    public Loan findCommend() {
        return borrowDao.findCommend();
    }

    private void TenderRecord(LoanTenderRecord loanTender, Loan borrow,
                              String ip, Member user, double account,
                              BigDecimal successAmount) {
        loanTender.setUser_id(user.getId());
        loanTender.setLoan_id(borrow.getId());
        loanTender.setPre_tender_money(BigDecimal.valueOf(account));
        loanTender.setSuccess_money(successAmount);
        loanTender.setBack_payment(BigDecimal.valueOf(0L));
        loanTender.setAddtime(MsDateUtils.getTime());
        loanTender.setAddip(ip);
        loanTender.setIs_auto(0);// 手动
        if (borrow.getIs_day() == 1) {// 天标
            loanTender.setInterest(loanTender.getSuccess_money().multiply(borrow.getApr().divide(new BigDecimal(36000), 10, 4)).multiply(new BigDecimal(borrow.getTime_limit())).setScale(2, 4));
        } else {
            if (borrow.getPay_style().equals(LoanRepayStyle.STYLE_1.getValue()+"")) {
                loanTender.setInterest(AverageCapitalPlusInterestUtils.getInterestCount(loanTender.getSuccess_money().doubleValue(), borrow.getApr().doubleValue()/100, borrow.getTime_limit()));
            } else {
                loanTender.setInterest(loanTender.getSuccess_money().multiply(borrow.getApr().divide(new BigDecimal(1200), 10, 4)).multiply(new BigDecimal(borrow.getTime_limit())).setScale(2, 4));
            }
        }
        loanTender.setBack_payment(loanTender.getSuccess_money().add(
                loanTender.getInterest()));
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void doTender(BigDecimal successAmount, Loan borrow, Member user, double account, String remoteIp, String packet_id)throws  NoticeException{

        LoanTenderRecord borrowTender = new LoanTenderRecord();
        // 第一步 投标
        int i = tender(successAmount,borrow.getId());
        if (i <= 0) {
            throw new NoticeException("此标已满,请勿再投");
        }
        // 封装投标数据
        TenderRecord(borrowTender, borrow, remoteIp, user, account, successAmount);
        // 第二步 产生投标数据
        if (loanTenderRecordService.addTenderLog(borrowTender, borrow.getMax_account(), user) == 0) {
            double tenderTotal = loanTenderRecordService
                    .getUserTenderSum(borrow.getId(), user.getId());
            if (((tenderTotal + account > borrow.getMax_account().doubleValue()))) {
                throw new NoticeException(
                        "该标您还剩投资额度为"
                                + (borrow.getMax_account()
                                .doubleValue() - tenderTotal));
            } else {
                throw new NoticeException("此标已满,请勿再投！");
            }
        }


        // 第三步 冻结投资金额，记录资金记录
        memberAccountService.OperAccount(remoteIp,successAmount,user.getId(),"投资<a  target='_blank' href='/bid/detail/"
                + borrow.getId()
                + "'>【"
                + borrow.getName()
                + "】</a>资金冻结。",AccountType.tender.getValue(),AccountFLow.FLOW_FROZEN.getValue());
    
        //第四部 使用红包
        redPacketService.useRedPacked(packet_id,borrow,successAmount,remoteIp);
        //第五步 奖励红包
        redPacketService.MEMBER_ID(user);

    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void verify(Loan loan, String status, AdminUser emp, String remark,String ip) throws  NoticeException{
        if (loan.getStatus().equals(LoanStatus.STATUS_4.getValue())) {
            if (Integer.parseInt(status) == 1) {
                loan.setStatus(LoanStatus.STATUS_5.getValue());
                List<LoanTenderRecord> borrowTenderList = loanTenderRecordService.getTenderLog(loan.getId());
                successLoan(loan,borrowTenderList,ip);
                addStay(loan,ip);
                addDueRecord(loan,ip);
                awardForTender(loan, borrowTenderList,ip);
                loan.setFull_verify_user(emp.getName());
                loan.setFull_verify_time(MsDateUtils.getTime());
                loan.setFull_verify_remark(remark);
                if (updateOptimistic(loan) == 0) {
                    throw new NoticeException("请您不要重复提交!");
                }
                //这里要再啦取一次
                miaoJudge(borrowDao.get(loan.getId()+""), ip);
            }
        } else {
            throw new NoticeException("该标已经审核");
        }

    }

    /**
     * 满标时候撤销
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void full_cancel(Loan borrow, AdminUser user,String ip)throws  NoticeException {
        borrow.setStatus(LoanStatus.STATUS_M5.getValue());
        borrow.setCancel_user(user.getName());
        borrow.setCancel_time(MsDateUtils.getTime());
        borrow.setCancel_remark("满标审核撤销招标");
        calculateFailBid(ip, borrow);
        if (updateOptimistic(borrow) == 0) {
            throw new NoticeException("请你不要重复提交可以吗");
        }
    }

    /**
     * 满标时候撤销
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void loan_cancel(Loan borrow, AdminUser user,String ip) throws  NoticeException{
        borrow.setStatus(LoanStatus.STATUS_M5.getValue());
        borrow.setCancel_user(user.getName());
        borrow.setCancel_time(MsDateUtils.getTime());
        borrow.setCancel_remark("审核中撤销招标");
        calculateFailBid(ip, borrow);
        if (updateOptimistic(borrow) == 0) {
            throw new NoticeException("请你不要重复提交可以吗");
        }
    }

    /**
     * 秒标自动还款
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private void miaoJudge(Loan loan, String ip) {
        if (loan.getStatus() == LoanStatus.STATUS_5.getValue() && loan.getLoan_category() == 10) {
            // 查询出用户需要还款的最近一期的待还信息
            LoanStay loanstay = loanStayService.findNext(loan.getId());
            loanStayService.repay(ip,loan,loanstay);
        }
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void autoLoan() {
        borrowDao.autoLoan(MsDateUtils.getTime());
    }

    public Loan findRookie() {
       return borrowDao.findRookie();
    }
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void autoCaculateLoan() {
       List<Loan>loans = borrowDao.findOverDue(MsDateUtils.getTime());
        for(int i=0;i<loans.size();i++){
            Loan loan = loans.get(i);
            loan.setStatus(LoanStatus.STATUS_M5.getValue());
            loan.setCancel_user("system");
            loan.setCancel_time(MsDateUtils.getTime());
            loan.setCancel_remark("审核中撤销招标");
            calculateFailBid("127.0.0.1", loan);
            if (updateOptimistic(loan) == 0) {
                throw new NoticeException("请你不要重复提交可以吗");
            }


        }
    }
}
